package dao

import (
	"context"
	"fmt"
	"time"

	"wxpay/internal/conf"
	"wxpay/pkg/mcontext"

	"github.com/patrickmn/go-cache"

	"go.uber.org/zap"

	"github.com/nsqio/go-nsq"

	"gorm.io/gorm"
)

type WxpayDao struct {
	*gorm.DB
	producer  *nsq.Producer
	consumers []*nsq.Consumer
	cache     *cache.Cache
}

func NewWxpayDao(db *gorm.DB) *WxpayDao {
	producer, err := nsq.NewProducer(conf.Conf.NSQAddr.NSQAddress, conf.Conf.NSQ)
	log := mcontext.Logger(context.Background())
	if err != nil {
		log.Fatal(err.Error())
		return nil
	}
	producer.SetLogger(&nsqLogger{}, nsq.LogLevelError)
	return &WxpayDao{
		DB:       db,
		producer: producer,
		cache:    cache.New(3*time.Hour, 3*time.Hour),
	}
}

func (d *WxpayDao) Close(ctx context.Context) {
	log := mcontext.Logger(ctx)
	if d.DB != nil {
		sqlDB, err := d.DB.DB()
		if err != nil {
			log.Fatal("could not get sqlDB", zap.Error(err))
		}
		if err = sqlDB.Close(); err != nil {
			log.Fatal(fmt.Sprintf("db connections close errors %s", err))
		}
		log.Info("db connections were closed")
	}
	if len(d.consumers) != 0 {
		for _, c := range d.consumers {
			c.Stop()
		}
		log.Info("nsq consumers were stopped")
	}
}

func (d *WxpayDao) Ping(ctx context.Context) error {
	session := d.DB.WithContext(ctx)
	db, err := session.DB()
	if err != nil {
		return err
	}
	return db.Ping()
}

func (d *WxpayDao) MchConfig() MchConfig {
	return NewMchConfigRepo(d.DB, d.producer, d.cache)
}

func (d *WxpayDao) Applyment() Applyment {
	return NewApplymentRepo(d.DB, d.producer, d.cache)
}

func (d *WxpayDao) Trade() Trade {
	return NewTradeRepo(d.DB, d.producer, d.cache)
}

func (d *WxpayDao) EventMessage() EventMessage {
	return NewMessageRepo(d.DB, d.producer)
}

func (d *WxpayDao) GetTx(ctx context.Context) *gorm.DB {
	return d.DB.WithContext(ctx)
}

func (d *WxpayDao) Lock() LockI {
	return NewLockRepo(d.DB)
}

func (d *WxpayDao) ProfitReceiver() ProfitReceiver {
	return NewProfitReceiverRepo(d.DB, d.producer)
}

func (d *WxpayDao) ProfitShare() ProfitShare {
	return NewProfitShareRepo(d.DB, d.producer)
}

func (d *WxpayDao) ProfitReturn() ProfitReturn {
	return NewProfitReturnRepo(d.DB, d.producer)
}

func (d *WxpayDao) Refund() Refund {
	return NewRefundRepo(d.DB, d.producer, d.cache)
}

func (d *WxpayDao) Transfer() Transfer {
	return NewTransferRepo(d.DB, d.producer, d.cache)
}

func (d *WxpayDao) Withdraw() Withdraw {
	return NewWithdrawRepo(d.DB, d.producer, d.cache)
}

func (d *WxpayDao) AliFaceToFaceSign() AliFaceToFaceSign {
	return NewAliFaceToFaceSignRepo(d.DB, d.producer, d.cache)
}

func (d *WxpayDao) AlipayAgent() AlipayAgent {
	return NewAlipayAgentRepo(d.DB, d.producer, d.cache)
}
